--- 战斗单位
---
--- @class Fighter:AbstractFighter
Fighter = ClientFight.CreateClass("Fighter", ClientFight.AbstractFighter)

--- @public
--- @return Fighter
function Fighter:ctor()
    self.groupFighterId = 0
    ---@type Fight
    self.fight = nil

    ---@type FightTeam
    self.fightTeam = nil

    --/** 伙伴ID */
    self.partnerId = 0
    --/** 名字 */
    self.name = ""
    --/** 队伍编号 */
    self.teamIndex = 0
    --/** 是否英雄 */
    self.leader = false
    --/** 是否为怪物 */
    self.monster = false
    --/** 是否为辅助 */
    self.assistant = false
    --/** 是否为天气 (木桩怪)*/
    self.weather = false

    --/** 是否为召唤物 */
    self.summons = false
    --/**召唤物类型*/
    ---@type SummonsType
    self.summonsType = nil
    --/**召唤者*/
    ---@type Fighter
    self.summonsCreater = nil
    --/** 召唤物创建时间 */
    self.summonsCreateFrame = -1
    --/**召唤物过期时间*/
    self.summonsExpireFrame = -1
    --/** 召唤物初始生存帧长 */
    self.lifeFrame = 0

    --/** 模型Id */
    self.modelId = 0
    --/** 等级 */
    self.level = 0
    --/** 星级 */
    self.star = 0
    --/** 专武等级 */
    self.weaponLevel = 0
    --/** pifu */
    self.skin = 0
    --/** 生命 */
    self.hp = 0
    --/** 能量 */
    self.energy = 0
    --/** 最大能量 */
    self.maxEnergy = 0
    --/** 英雄配置 */

    ---@type T_heroBean
    self.heroBean = nil
    --/** 技能信息 */
    ---@type number[]
    self.skillIds = nil
    --/**
    --* 增加技能
    --* 各种其他模块附加过来的技能
    --* */
    ---@type table<number,number>
    self.addSkills = nil

    --/** 参数 */
    ---@type table<string,string>
    self.paramemters = {};
    --/** 参数2 */
    ---@type table<string,any>
    self.parametersByObject = {}

    --/** 死亡次数 */
    self.dieTimes = 0

    --/**
    --* 角色死亡状态
    --* 由于现有逻辑全部使用hp来判断死亡,用这个标识来判断是否执行过死亡逻辑，不然会出现重复死亡的现象
    --*/
    self.dieStatus = false

    --/**
    --* 站位
    --* 1,2 前排
    --* 3，4，5 后排
    --* 援助英雄顶替死亡的英雄站位
    --* */
    self.site = 0
    --/** 坐标 */
    ---@type Vector2
    self.position = Vector2.New(0, 0)

    --/** 方向 */
    self.direction = 0
    --/** 形状 */
    ---@type Rectangle2
    self.shape = nil
    --/** 行为树 */

    ---@type BehaviourTree
    self.aiTree = nil
    --/** 是否在跑回 */

    self.moveBack = false

    --/** 普通攻击 */

    ---@type FightSkill
    self.normalAttack = nil
    --/** 拥有的技能 */

    ---@type FightSkill[]
    self.skills = {}
    --/** 拥有的被动技能 */

    ---@type FightSkill[]
    self.passiveskills = {}

    --/** 移动行为 */
    ---@type table<string,any>
    self.moveAction = nil
    --/** 移动攻击行为(冲锋等) */
    ---@type table<string,any>
    self.moveAttackAction = nil

    --/** 决斗目标 */

    ---@type Fighter
    self.duelTarget = nil
    --/** 准备使用技能 */

    ---@type FightSkill
    self.prepareSkill = nil
    --/** 正在使用技能 */

    ---@type FightUsingSkill
    self.usingSkill = nil
    --/** 忽略使用的技能（选择目标为空的技能） */

    ---@type table<number,boolean>
    self.skipSkill = {};
    --/** 准备阶段目标 */

    ---@type Fighter
    self.prepareTarget = nil
    --/**是否重置准备阶段目标*/

    self.resetPrepareTarget = false
    --/** 移动朝向目标 */

    ---@type Fighter
    self.moveTarget = nil
    --/**
    --* 移动朝向地点
    --* 对于没有目标单位只需要移动到指定点的召唤物用
    --* 或者 被挂了某种特殊buff 没有目标只有目标点
    --* */

    ---@type Vector2
    self.movePosition = Vector2.New(0, 0)
    --/** 寻路时,目标所在位置 */

    ---@type Vector2
    self.searchTargetPositon = Vector2.New(0, 0)
    --/** 移动朝向方向（跑回时候使用） */

    self.moveDirection = 0
    --/** 嘲讽朝向目标 */

    ---@type Fighter
    self.sneerTarget = nil
    --/** 主角 */

    ---@type Fighter
    self.leaderFighter = nil
    --/** 上一次攻击目标 */

    ---@type Fighter
    self.lastAttackFighter = nil
    --/** 上一次普攻目标 */

    ---@type Fighter
    self.lastNormalAttackFighter = nil
    --/**
    --* 永久BUFF（被动）
    --* key:buff唯一id
    --* */

    ---@type table<number,FighterBuff>
    self.permanentBuffs = {}
    --/**
    --* 战斗BUFF
    --* key:buff 唯一id
    --* */

    ---@type table<number,FighterBuff>
    self.buffs = {}
    --/** 冷却列表 */

    ---@type table<number,Cooldown>
    self.cooldowns = {}
    --/** 警戒范围1 */
    ---@type Rectangle2
    self.alertRange1 = nil
    --/** 警戒范围2 */
    ---@type Rectangle2
    self.alertRange2 = nil

    --/**
    --* 战斗数值记录<br/>
    --* key {@link FightStatisticsEnum}
    --*/

    ---@type FighterStats
    self.fighterStats = FighterStats.New()
    --/**
    --* buff强行修改下次技能的 目标选取规则
    --*/

    ---@type table<number,BuffSetSkillRuleSelector>
    self.targetRuleSelectorByBuff = {}

    --/** 我的光环 正在生效  value里面存储了 我的光环正在生效的buff*/

    ---@type table<number,table<number,BuffSetSkillRuleSelector>>
    self.haloChildren = {}
    --/** 主动技能触发的时效光环 */

    ---@type table<FighterBuff,boolean>
    self.activHaloBuff = {}
    --/** 护盾池 */

    self.defeatPool = 0

    --buffId  value = 参数名称和 其对应的数值>

    ---@type table<number,table<DynamicParam,string>>
    self.buffDynamicParam = {}
    --skillId  value = 参数名称和 其对应的数值>

    ---@type table<number,table<DynamicParam,string>>
    self.skillDynamicParam = {}

    ---@type table<number,T_buffBean>
    self.buffDynamic = {}

    ---@type table<number,T_buffBean>
    self.skillDynamic = {}
    --/** 最后一次 伤害我的人 */
    self.lastDamageMe = 0

    self.summonId = 0

    ---@type Fighter
    self.puppet = nil
end
function Fighter:setHp(hp)
    self.hp = hp
end

function Fighter:isDie()
    return self.hp <= 0;
end
function Fighter:incrementDieTimes()
    self.dieTimes = self.dieTimes + 1
end

function Fighter:isRangedCLass()
    local e = self.heroBean.f_HeroType
    if e == HeroConst.Hero_Type_MO_DAO_SHI or e == HeroConst.Hero_Type_MU_SHI or e == HeroConst.Hero_Type_YOU_XIA then
        return true
    end
    return false
end
function Fighter:isFrontRow()
    if self.site == 1 or self.site == 2 then
        return true
    end
    return false
end

function Fighter:print()
    return "Fighter(" .. "id=" .. self.fighterId .. ",modelId=" .. self.modelId .. ",pos=" .. getJsonStr(self.position) .. ")"
end
function Fighter:printAttr()
    return "Fighter[" .. self.fighterId .. "](" .. getJsonStr(self.totalAttribute.attributes) .. ")"
end
---计算释放技能需要的能量
---@param skill FightSkill
function Fighter:calUseSp(skill)
    local skillBean = skill.skillBean
    if skillBean.f_UseSP ==nil or skillBean.f_UseSP <= 0 then
        return 0
    end
    ---使用技能时, 能量减免
    local energyCost = math.floor(FighterAttributeManager.getFightAttr(self, FighterAttributeEnum.ENERGY_COST))
    local realUseSp = skillBean.f_UseSP - energyCost
    return realUseSp < 0 and 0 or realUseSp
end
---@param ruleSelector TargetRuleSelector
function Fighter:updateSkillTargetRuleSelectorByBuff(id, ruleSelector, ...)
    local args = { ... }
    self.targetRuleSelectorByBuff[id] = BuffSetSkillRuleSelector.New(id, ruleSelector, args)
end
---@return BuffSetSkillRuleSelector
function Fighter:removeSkillTargetRuleSelectorByBuff(id)
    local v = self.targetRuleSelectorByBuff[id]
    self.targetRuleSelectorByBuff[id] = nil
    return v
end
---@return BuffSetSkillRuleSelector
function Fighter:getByBuffUUID(id)
    return self.targetRuleSelectorByBuff[id]
end
---@return BuffSetSkillRuleSelector
function Fighter:randomSkillTargetRuleSelector()
    for k, v in pairs(self.targetRuleSelectorByBuff) do
        return v
    end
    return nil
end
---@param fighter Fighter
function Fighter:equals(fighter)
    if self == fighter then
        return true
    end
    if self.__cname ~= fighter.__cname then
        return false
    end
    return self.fighterId == fighter.fighterId
end
---@param skill FightSkill
function Fighter:setPrepareSkill(skill)
    self.prepareSkill = skill
    if (skill ~= nil) then
        table.clear(skill.fighterSelectStates)
    end
end
function Fighter:isRealSummons()
    return self:isSummons() and self.summonsType == SummonsType.ENTITY
end

function Fighter:getTeamIndex()
    return self.fightTeam.getTeamIndex();
end

function Fighter:checkOverHitTarget()
    --检查当前英雄大招是否有目标
    if (FighterStateEnum.is(self, FighterStateEnum.CAN_NOT_USE_SKILL)
            and FighterStateEnum.is(self, FighterStateEnum.CAN_NOT_NORMAL_ATTACK)) then
        --不能使用技能不能攻击
        return false;
    end
    if self:isDie() then
        return false;
    end
    if table.contains(self.totalSign.signs, FighterSignEnum.TAG_1000) then
        return false;
    end

    for k, skill in pairs(self.skills) do
        local prepareSkill = {}
        if self:calUseSp(skill) > 0 then
            --大招
            local skip = false
            if self.skipSkill[skill.skillBean.f_SkillID] then
                skip = true
            end
            if skill.skillBean.f_TriggerType == SkillActionTypeEnum.TRIGGER then
                skip = true
            end
            if not SkillLimitType:action(self, skill.skillBean) then
                skip = true
            end
            if self.energy < self:calUseSp(skill) then
                skip = true
            end
            if ClientFight.SkillClientManager.isCooldowning(self, skill.skillId) then
                skip = true
            end

            prepareSkill = skill
            local inAttackRange = false;
            local target = ClientFight.SkillClientManager.selectAttackTarget(self.fight, self, prepareSkill, self.position, nil, false);
            if AttackUtils.getAttackShape(self, prepareSkill) == nil then
                inAttackRange = true;
            else
                if target == nil then
                    inAttackRange = true;
                else
                    inAttackRange = DistanceUtil.overlap(self.position, AttackUtils.getAttackShape(self, prepareSkill),
                            target.position, target.shape)
                end
            end
            --判断是否在攻击范围内
            if inAttackRange and not skip then
                return true
            else
                return false
            end

        end
    end

end

function Fighter:getOverHit()
    for k, skill in pairs(self.skills) do
        local prepareSkill = {}
        if self:calUseSp(skill) > 0 then
            return skill;
        end
    end
end

function Fighter:getOverHitTarget()
    for k, skill in pairs(self.skills) do
        local prepareSkill = {}
        if self:calUseSp(skill) > 0 then
            --大招
            local skip = false
            if self.skipSkill[skill.skillBean.f_SkillID] then
                skip = true
            end
            if skill.skillBean.f_TriggerType == SkillActionTypeEnum.TRIGGER then
                skip = true
            end
            if not SkillLimitType:action(self, skill.skillBean) then
                skip = true
            end
            if self.energy < self:calUseSp(skill) then
                skip = true
            end
            if ClientFight.SkillClientManager.isCooldowning(self, skill.skillId) then
                skip = true
            end

            prepareSkill = skill
            local target = ClientFight.SkillClientManager.selectAttackTarget(self.fight, self, prepareSkill, self.position, nil, false);
            return target
        end
    end
end

function Fighter:isGroupFighter()
    return self.fighterId >= self.groupFighterId;
end

function Fighter:isSummons()
    return self.summons;
end

function Fighter:isRangedtype()
    if self.heroBean.f_HeroType == HeroConst.Hero_Type_MO_DAO_SHI or self.heroBean.f_HeroType == HeroConst.Hero_Type_MU_SHI or self.heroBean.f_HeroType == HeroConst.Hero_Type_YOU_XIA then
        return true;
    else
        return false;
    end
end
